package juctest;

import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author 江岸
 * @version V1.0
 * @ClassName: LockTest
 * @description: 等待唤醒
 * @date 2021/3/1917:04
 * @since V1.0
 */
public class WaitAndNotifyTest2{
    public static void main(String[] args) {
        Clerk2 clerk2 = new Clerk2();
        Productor2 productor2 = new Productor2(clerk2);
        Consumer2 consumer2 = new Consumer2(clerk2);
        new Thread(productor2, "生产者A").start();
        new Thread(consumer2, "消费者B").start();
        new Thread(productor2, "生产者C").start();
        new Thread(consumer2, "消费者D").start();
    }
}

//店员
class Clerk2 {
    private int product = 0;//共享数据
    private Lock lock = new ReentrantLock();//创建锁对象
    private Condition condition = lock.newCondition();//获取condition实例

    /**
     * 使用lock同步锁，就不需要sychronized关键字了，需要创建lock对象和condition实例。
     * condition的await()方法、signal()方法和signalAll()方法分别与wait()方法、
     * notify()方法和notifyAll()方法对应。
     *必须在condition.await()方法调用之前调用lock.lock()代码获得同步监视器，不然会报错。
     *
     */
    public void get() { //进货
        lock.lock();//上锁
        try {
            while (product >= 1) {
                System.out.println("产品已满");
                try {
                    condition.await();//满了就等待；阻塞，释放锁
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + ":" + (++product));
            condition.signalAll();//没满就可以进货；唤醒所有线程
        }finally {
            lock.unlock();//释放锁
        }

    }

    public  void sell() {//卖货
        lock.lock();//上锁
        try {
            while (product <= 0) {
                System.out.println("缺货");
                try {
                    condition.await();//缺货就等待
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println(Thread.currentThread().getName() + ":" + (--product));
            condition.signalAll();//不缺货就可以卖
        }finally {
            lock.unlock();//释放锁
        }
    }
}

//生产者
class Productor2 implements Runnable {
    private Clerk2 clerk2;

    public Productor2(Clerk2 clerk2) {
        this.clerk2 = clerk2;
    }

    @Override
    public void run() {
        for (int i = 0; i < 21; i++) {
            clerk2.get();
        }
    }
}

//消费者
class Consumer2 implements Runnable {
    private Clerk2 clerk2;

    public Consumer2(Clerk2 clerk2) {
        this.clerk2 = clerk2;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(300);//睡0.2秒
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        for (int i = 0; i < 21; i++) {
            clerk2.sell();
        }
    }
}